package com.artnology.independence.model.relationships;


import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Paint;
import java.awt.Stroke;
import java.util.Set;

import org.apache.commons.collections15.Predicate;

import com.artnology.independence.Activator;
import com.artnology.independence.model.DVGraphModel;
import com.artnology.independence.model.DVModelObject;
import com.artnology.independence.model.DVNode;
import com.artnology.independence.views.DependencyView;

import edu.uci.ics.jung.algorithms.filters.EdgePredicateFilter;


public abstract class DVReference extends DVModelObject {
	
	protected static final Stroke thickerStroke = new BasicStroke(3.0f);
	private DVNode referenceToNode = null;
	private DVNode referenceFromNode = null;
	
	public DVNode getReferenceFromNode() {
		return referenceFromNode;
	}

	public void setReferenceFromNode(DVNode referenceFromNode) {
		this.referenceFromNode = referenceFromNode;
	}

	protected int weight = 1;

	public DVReference(String name, DVGraphModel model, DVNode referencedNode, DVNode referenceFromNode) {
		super(name, model);
		this.referenceToNode = referencedNode;
		this.referenceFromNode = referenceFromNode;
	}
	
	public boolean isPhantom() {
		return getGraphModel().getAllPhantomTypes().contains(getReferencedNode());
	}


	public DVNode getReferencedNode() {
		return referenceToNode;
	}


	public String toString() {
		return getLabel();
	}

	public String getLabel() {
		String label = getPrefix();
		if (Activator.getDefault().getPrefStore().getBoolean(DependencyView.SHOW_RELATIONSHIP_NAMES) && getName() != null){
			label += " (" + getName() + ")";
		}
		return label;
	}
	
	public abstract String getPrefix();
	
	public static EdgePredicateFilter<DVNode, DVReference> getEdgePredicateFilter(final Set<Class<? extends DVReference>> filterReferenceTypes) {
		return new EdgePredicateFilter<DVNode, DVReference>(new Predicate<DVReference>() {
			@Override
			public boolean evaluate(DVReference ref) {
				return !(filterReferenceTypes.contains(ref.getClass()));
			}
			
		});
	}
	
	
	public abstract boolean crossesPackageBorder();
	
	public Stroke getStroke() {
		if (Activator.getDefault().getPrefStore().getBoolean(DependencyView.INDICATE_CROSS_PACKAGE_EDGE) && this.crossesPackageBorder()) {
			return thickerStroke;
		}
		return new BasicStroke(getDrawingScalingFactor());
	}
	
	public Paint getEdgeDrawPaint() {
		if (Activator.getDefault().getPrefStore().getBoolean(DependencyView.INDICATE_CROSS_PACKAGE_EDGE) && this.crossesPackageBorder()) {
			return Color.BLUE;
		} else {
			return Color.BLACK;
		}
	}

	public void increaseWeight() {
		weight++;
	}
	
	@Override
	public float getDrawingScalingFactor() {
		if (isCurrentlySelected()){
			return SCALING_FACTOR_FOR_SELECTED_ELEMENTS * weight;
		}
		return weight;
	}
	
	@Override
	public boolean equals(Object o1) {
		if (!(o1 instanceof DVReference)) {
			return false;
		}
		DVReference otherRef = (DVReference) o1;
		if ( !(otherRef.getReferencedNode().equals(this.getReferencedNode()) && otherRef.getReferenceFromNode().equals(this.getReferenceFromNode()))) {
			return false;
		}	
		if (otherRef.getName() == null && this.getName() != null) {
			return false;
		}else if (otherRef.getName() != null && this.getName() == null) {
			return false;
		} else if (otherRef.getName() == null && this.getName() == null) {
			return true;
		} else if (otherRef.getName().equals(this.getName())) {
			return true;
		}
		return false;
		
	}

	@Override
	public int hashCode() {
		int hashcode = getReferencedNode().hashCode() + getReferenceFromNode().hashCode();
		if (getName() != null) {
			hashcode += getName().hashCode();
		}
		return hashcode;
	}

	
	
	

}
